package com.mymoney.ws.client;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.regex.Pattern;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.preference.PreferenceManager;
import android.util.Log;
import android.util.Patterns;

import com.mymoney.constants.Constants;
import com.mymoney.exceptions.CommunicationException;
import com.mymoney.helpers.IOHelper;

/**
 * @author georgi.tsankov The httpClient used in communication with the server
 */
public class SSLHttpClient extends DefaultHttpClient {

    private static String TAG = "SSLHttpClient";
    
    private int NUMBER_OF_ATTEMPTS = 3;

    private Context context;

    private HttpClient httpClient;

    public SSLHttpClient(Context context) {
        this.context = context;
        
        if(isOnline())
        this.httpClient = CustomSSLSocketFactory.getCustomHttpClient(context);
    }
    
	private boolean isOnline() {
	    ConnectivityManager cm =
	        (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

	    return cm.getActiveNetworkInfo() != null && 
	       cm.getActiveNetworkInfo().isConnectedOrConnecting();
	}


    public String get(String path) throws ClientProtocolException,
                    IOException, Exception {
    	String result = null;
        HttpGet httpGet = new HttpGet(path);
        Log.d(TAG, "Executing GET Request:\n" + path);
        result = executeRequest(httpGet);
        return result;
    }


    private String executeRequest(HttpRequestBase request) throws CommunicationException, ClientProtocolException, IOException {
        HttpResponse httpResponse = null;
        String responseString = null;
        
        if(isOnline())
        {
        	int attemptCounter = 0;
	        if (getPrimaryAccount() != null) {
	            request.setHeader("From", getPrimaryAccount());
	        }
	        do
	        {
	        	httpResponse = httpClient.execute(request);
	        	attemptCounter++;
	        }
	        while(httpResponse == null && attemptCounter < NUMBER_OF_ATTEMPTS);
	
	        if(httpResponse != null)
	        {
		        if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
		            String responseBody = IOHelper.parseStream(httpResponse.getEntity().getContent());
		            Log.d(TAG, "Response body:\n" + responseBody);
		            responseString = responseBody;
		        } else {
		            Log.w(TAG, "Communicating with the server returned http status: "
		                            + httpResponse.getStatusLine().getStatusCode());
		            Log.w(TAG,
		                            "The body for the response is: "
		                                            + IOHelper.parseStream(httpResponse.getEntity()
		                                                            .getContent()));
		        }
	        }
	        else
	        {
	        	throw new CommunicationException("Проблем при комуникация със сървъра. Моля да ни извините. Опитайте пак малко по-късно.");
	        }
        }
        else
        {
        	throw new CommunicationException("Моля проверете връзката си с Интернет");
        }
        
        return responseString;
    }

    
    public String put(String path, String requestBody) throws ClientProtocolException, CommunicationException, IOException  {
    	String result = null;
        HttpPut httpPut = new HttpPut(path);
        httpPut.setEntity(prepareStringEntity(requestBody));
        Log.v(TAG, "Executing request:\n" + requestBody);
        Log.v(TAG, "Target URL: " + path);
        result = executeRequest(httpPut);
        return result;

    }


    public String post(String path, String requestBody) throws ClientProtocolException, CommunicationException, IOException {
    	String result = null;
        HttpPost httpPost = new HttpPost(path);
        httpPost.setEntity(prepareStringEntity(requestBody));
        Log.v(TAG, "Executing request:\n" + requestBody);
        Log.v(TAG, "Target URL: " + path);
        result = executeRequest(httpPost);
        return result;

    }

    public String post(String path) throws ClientProtocolException, CommunicationException, IOException {
    	String result = null;
        HttpPost httpPost = new HttpPost(path);
        Log.v(TAG, "Target URL: " + path);
        result = executeRequest(httpPost);
        return result;
    }

    private StringEntity prepareStringEntity(String requestBody) {
        StringEntity entity = null;
        try {
            entity = new StringEntity(requestBody, "UTF-8");
            entity.setContentType("application/json");
        } catch (UnsupportedEncodingException e) {
            Log.e(TAG, "Error while preparing request", e);
        }
        return entity;
    }

    @SuppressWarnings("unused") //for future needs
	private String getAddress() {
        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context
                        .getApplicationContext());
        return sharedPrefs.getString(Constants.SERVER_ADDRESS_KEY, null);

    }
    
    private String getPrimaryAccount() {
    	
    	String primaryEmail = "";
    	Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
    	Account[] accounts = AccountManager.get(context).getAccounts();
    	for (Account account : accounts) {
    	    if (emailPattern.matcher(account.name).matches()) {
    	    	primaryEmail = account.name;
    	    }
    	}
    	
    	return primaryEmail;
    }

}
